1 /**
2  * A flat image storage type.
3  * Useful for your underlying contextual needs.
4  * 
5  * License:
6  *              Copyright Devisualization (Richard Andrew Cattermole) 2014 - 2017.
7  *     Distributed under the Boost Software License, Version 1.0.
8  *        (See accompanying file LICENSE_1_0.txt or copy at
9  *              http://www.boost.org/LICENSE_1_0.txt)
10  */
11 module devisualization.image.storage.flat;
12 import std.experimental.color : isColor;
13 import stdx.allocator : IAllocator, theAllocator;
14 
15 /**
16  * Represents an image using a flat array.
17  *
18  * Because the usage of multiplication is required to index and assign,
19  * it is not recommend to be used outside of drawing contexts.
20  * Where this is the least expensive option for a buffer to draw upon.
21  * 
22  * Will automatically deallocate its memory when it goes out of scope.
23  * Should not be copied or moved around.
24  * 
25  * See_Also:
26  *      ImageStorage
27  */
28 struct FlatImageStorage(Color) if (isColor!Color) {
29     private {
30         size_t width_, height_;
31         IAllocator allocator;
32         Color[] data;
33     }
34     
35     ///
36     this(size_t width, size_t height, IAllocator allocator = theAllocator()) @trusted {
37         import stdx.allocator : makeArray;
38         this.allocator = allocator;
39 
40         width_ = width;
41         height_ = height;
42         
43         data = allocator.makeArray!(Color)(width * height);
44     }
45 
46 	~this() @trusted {
47 		import stdx.allocator : dispose;
48 
49 		if (!__ctfe && data !is null)
50 			allocator.dispose(data);
51 	}
52     
53     @property {
54         ///
55         size_t width() @nogc nothrow @safe { return width_; }
56 
57         ///
58         size_t height() @nogc nothrow @safe { return height_; }
59     }
60 
61     ///
62     Color getPixel(size_t x, size_t y) @nogc @safe { return data[(y * width) + x]; }
63 
64     ///
65     void setPixel(size_t x, size_t y, Color value) @nogc @safe { data[(y * width) + x] = value; }
66 
67     ///
68     Color opIndex(size_t x, size_t y) @nogc  @safe{ return getPixel(x, y); }
69 
70     ///
71     void opIndexAssign(Color value, size_t x, size_t y) @nogc @safe { setPixel(x, y, value); }
72     
73     ///
74     bool resize(size_t newWidth, size_t newHeight) @trusted {
75         import stdx.allocator : dispose, makeArray;
76         import std.algorithm : min;
77 
78         scope(failure)
79             return false;
80 
81         Color[] newData;
82 
83         if (newWidth == 0 || newHeight == 0) {
84         } else {
85             newData = allocator.makeArray!(Color)(newWidth * newHeight);
86             
87             size_t minWidth = min(width, newWidth);
88             size_t offsetOld, offsetNew;
89             foreach(y; 0 .. min(height, newHeight)) {
90                 newData[offsetNew .. offsetNew + minWidth] = data[offsetOld .. offsetOld + minWidth];
91                 
92                 offsetOld += width;
93                 offsetNew += newWidth;
94             }
95             
96         }
97 
98         allocator.dispose(data);
99 
100         width_ = newWidth;
101         height_ = newHeight;
102         data = newData;
103 
104         return true;
105     }
106     
107     /**
108      * Get the array that backs this image storage type
109      *
110      * This is considered an unsafe operation.
111      * Do not use unless you know what you are doing.
112      *
113      * Returns:
114      *      The backing array containing the pixels
115      */
116     immutable(Color[]) __pixelsRawArray() {
117         return cast(immutable)data;
118     }
119 }